実習3:Crispy Forms を自分で確認してみよう
インストール
既にCONDA環境になっているのであれば抜けておきましょう。
code: bash
$ conda deactivate
conda環境を作ります。
code: bash
$ conda create -y -n django python=3.6
$ conda activate django
次にパッケージをインストールしましょう。
code: bash
$ pip install django django-crispy-forms django-extensions django-debug-toolbar aldjemy sqlalchemy python-dotenv
プロジェクトとアプリケーションを作成
code: bash
$ django-admin startproject django_deno
$ cd django_demo
$ python manage.py startapp crispy
settings.py に crispy_forms と django-extensions を追加しましょう。
code: django_demo/settings.py
INSTALLED_APPS = [
# ...
'django_extensions',
'crispy_forms',
]
# ...
STATIC_URL = '/static/'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
try:
from dotenv import load_dotenv
load_dotenv()
except:
pass
if DEBUG:
def show_toolbar(request):
return not request.is_ajax()
MIDDLEWARE += (
'debug_toolbar.middleware.DebugToolbarMiddleware',
)
INSTALLED_APPS += (
'debug_toolbar',
)
INTERNAL_IPS = ('127.0.0.1', )
DEBUG_TOOLBAR_CONFIG = {
'SHOW_TOOLBAR_CALLBACK' : show_toolbar,
}
アプリケーションを登録
settings,py の INSTALLED_APPSに、このアプリケーション crispy を登録します。
code: django_demo/settings.py
INSTALLED_APPS = [
# ...
'crispy',
]
プロジェクトの urls.py にも crispy のURLパターンを追加します。
code: django_demo/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('crispy/', include('crispy.urls')),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
次にベーステンプレートを作成します。
ここで、CDNを指定してBootstrapを読み込むようにしています。
いくつかのコンポーネントで jQuery, Popper.js などの JavaScript プラグインが必要なので、<script> を </body> の直前に次の順番で記述します。
code: crispy/templates/crispy_base.htnml
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<title>Django Demo!</title>
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
<h1 class="mt-2">Django Demo</h1>
<hr class="mt-0 mb-4">
{% block content %}
{% endblock %}
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
</body>
</html
モデルクラスを作成
製品情報を保存するモデルクラス Productを作成しましょう。
code: crispy/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=130)
description = models.TextField(blank=True)
price = models.FloatField(blank=True)
ビューの作成
汎用ビューの CreateViewを使ってビューを作成しましょう。
code: crispy/views.py
from django.views.generic import CreateView
from .models import Product
class ProductCreateView(CreateView):
model = Product
fields = ('name', 'description', 'price')
template_name = 'crispy_product.html'
テンプレートファイルを用意します。
crispy_forms を使わないテンプレート
code: crispy/templates/crispy_product1.html
{% extends 'crispy_base.html' %}
{% block content %}
<form method="post" novalidate>
{% csrf_token %}
{{ form }}
<button type="submit" class="btn btn-success">Save Product</button>
</form>
{% endblock %}
crispy_forms の crispyフィルターを使ったテンプレート
code: crispy/templates/crispy_product2.html
{% extends 'crispy_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-success">Save Product</button>
</form>
{% endblock %}
crispy_froms の as_crispy_fields フィルターを使ったテンプレート
code: crispy/template/crispy_produt3.html
{% extends 'crispy_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post" novalidate>
{% csrf_token %}
<div class="row">
<div class="col-6">
{{ form.name|as_crispy_field }}
</div>
<div class="col-6">
{{ form.price|as_crispy_field }}
</div>
</div>
{{ form.description|as_crispy_field }}
<button type="submit" class="btn btn-success">Save Product</button>
</form>
{% endblock %}
code: crispy/urls.py
from django.urls import path, include
from . import views
app_name = 'crispy'
urlpatterns = [
path('add/', views.ProductCreateView.as_view(), name='product_create'),
]
データベースの作成
code: bash
$ python manage.py makemaigrations
$ python manage.py maigrate
はじめのて起動
show_urls でURLを確認してから、 runserverで アプリケーションを起動してみましょう。
code: bash
$ python manage.py show_urls
$ python manage.py runserver
ブラウザで次のURLにアクセスしてみましょう。
この状態ではエラーになるはずです。
3つのテンプレートファイルを入れ替えてレンダリングがどう変わるか確認してみましょう。
FormHelper を使ってみよう
汎用ビューの CreateViewクラスはフォームを作成することができるため、ここまでのところでフォームクラスを用意していませんでしたが、FormHelper を使うので次のように定義します。
code: crispy/forms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from product.models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('name', 'description', 'price')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Save Product'))
また、データ一覧と更新を行うビューもここで定義しておきます。
code: crispy/views.py
from django.views.generic import CreateView, UpdateView, ListView
from django.urls import reverse_lazy
from .models import Product
from .forms import ProductForm
class ProductListView(ListView):
model = Product
fields = ('name', 'email')
template_name = 'crispy_product_list.html'
class ProductCreateView(CreateView):
model = Product
template_name = 'crispy_product.html'
success_url = reverse_lazy('crispy:product_list')
class ProductUpdateView(UpdateView):
model = Product
form_class = ProductForm
template_name = 'crispy_product_update.html'
success_url = reverse_lazy('crispy:product_list')
テンプレートはこうです。
code:crispy/templtes/crispy_product_list.html
{% extends "crispy_base.html" %}
{% block content %}
<a href="{% url 'formdemo:product_create' %}"> プロダクト追加</a>
<h2>プロダクト一覧</h2>
{% for product in product_list %}
<p>
プロダクト:{{ product.name }} / 詳細:{{ product.description }}
<a href="{% url 'formdemo:product_update' product.pk %}">修正</a> </p>
{% endfor %}
{% endblock %}
code: crispy/templates/crispy_product_update.html
{% extends 'crispy_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% crispy form %}
{% endblock %}
code: crispy/urls.py
from django.urls import path, include
from . import views
app_name = 'crispy'
urlpatterns = [
path('', views.ProductListView.as_view(), name='produt_list'),
path('list/', views.ProductListView.as_view(), name='product_list'),
path('add/', views.ProductCreateView.as_view(), name='product_create'),
path('edit/<int:pk>/',
views.ProductUpdateView.as_view(), name='product_update')
]
FromHelper でフォームをレイアウトしてみる
FromHelper でフォームをレイアウトしてみましょう。
code: crispy/forms.py
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from product.models import Product
from crispy_forms.layout import Layout, Submit, Row, Column
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('name', 'description', 'price')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post' # get or post
self.helper.layout = Layout(
Row(
Column('name', css_class='form-group col-md-6 mb-0'),
Column('price', css_class='form-group col-md-6 mb-0'),
css_class='form-row'
),
'description',
Submit('submit', 'Save Product')
)
宿題
既にお気づきのように、このアプリケーションはデータを追加/修正することしかできません。
指定したデータを削除するため修正してみましょう。